home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / ip / dns / dnsparse-2.0 / dnslex.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-09-11  |  5.2 KB  |  246 lines

  1. #ifndef lint
  2. char rcsid[] = "$Id: dnslex.c,v 2.0 90/09/11 11:07:31 hakanson Rel $";
  3. #endif /* lint */
  4.  
  5. /*
  6.  * A lexical analyzer for DNS master files.
  7.  *   Marion Hakanson (hakanson@cse.ogi.edu)
  8.  *   Oregon Graduate Institute of Science and Technology
  9.  *
  10.  * Copyright (c) 1990, Marion Hakanson.
  11.  *
  12.  * You may distribute under the terms of the GNU General Public License
  13.  * as specified in the README file that comes with the dnsparse kit.
  14.  *
  15.  * This program accepts as input DNS master files, as described
  16.  * in RFC-1035.  It breaks up the input in such a way that a single
  17.  * resource record (RR) is output on a single line, with a delimiter
  18.  * character between each token (or field) of the RR.
  19.  *
  20.  * The output format was designed for consumption by programs such
  21.  * as awk or perl, so the delimiter character can be used to quickly
  22.  * split the RR into its components.
  23.  *
  24.  * It is likely that one could change the add_*char, end_word, and
  25.  * end_line macros to put chars into a separate buffer or perform
  26.  * some other function, and thus use do_dblex() inside a full parser
  27.  * program (such as a DNS server).
  28.  *
  29.  * One other thing.  This program could probably have been written
  30.  * in lex instead of C, but lex has a number of builtin limits to
  31.  * the length of expressions (where RFC-1035 does not, in all cases).
  32.  * I probably should have used flex instead, but the simple state
  33.  * machine below was not that tough to implement, and it's also
  34.  * pretty quick and pretty small.
  35.  */
  36.  
  37. #include <stdio.h>
  38.  
  39. #define strchr index    /* system dependent */
  40. #define strrchr index
  41. extern char *strchr(), *strrchr();
  42.  
  43. extern getopt(), optind, opterr;
  44. extern char *optarg;
  45.  
  46. #define FALSE 0
  47. #define TRUE  1
  48.  
  49. /* Globals */
  50. char *prog;
  51.  
  52.  
  53. usage_and_die()
  54. {
  55.     fprintf(stderr, "usage: %s [-d <char>]\n", prog);
  56.     exit(1);
  57. }
  58.  
  59.  
  60.  
  61. /* Special (to DNS) chars we output in printed (non-decimal-escaped) form */
  62. #define SPECS " \t\n;()\\.@"    /* for consumption by strchr() */
  63. #define SPECP " \\t\\n;()\\.@"    /* for consumption by fprintf() */
  64.  
  65.  
  66. main(argc, argv)
  67.     int  argc;
  68.     char **argv;
  69. {
  70. int opt;
  71.  
  72. /* Defaults */
  73. register FILE    *ifile = stdin,
  74.         *ofile = stdout;
  75. char delim = ':';
  76.  
  77. if ( prog = strrchr(argv[0], '/') )
  78.     prog++;
  79. else
  80.     prog = argv[0];
  81.  
  82. /* Parse the arguments */
  83. opterr = 0;
  84. while ( (opt = getopt(argc, argv, "d:")) != EOF )
  85.     switch ((char)opt)
  86.     {
  87.     case '?':
  88.         usage_and_die();
  89.         break;
  90.     case 'd':
  91.         delim = *optarg;
  92.         break;
  93.     default:
  94.         /* Not supposed to happen. */
  95.         fprintf(stderr, "%s: Hey getopt(3)!  Wake up!\n", prog);
  96.         usage_and_die();
  97.         break;
  98.     }
  99.         
  100.  
  101. /* This saves checking every char output against delim */
  102. if ( strchr(SPECS, delim) != NULL ) {
  103.     fprintf(stderr, "%s: delimiter '%c' cannot be one of '%s'.\n",
  104.             prog, delim, SPECP);
  105.     exit(1);
  106. }
  107.  
  108. (void) do_dblex(ifile, ofile, delim);
  109.  
  110. exit(0);
  111. }
  112.  
  113.  
  114.  
  115. int
  116. do_dblex (ifile, ofile, delim)
  117.     register FILE *ifile, *ofile;
  118.     char delim;
  119. {
  120. register int c;
  121. register int newword = FALSE;
  122. register int wordlen = 0;
  123. register int linelen = 0;
  124. int inbrackets = FALSE;
  125. int inquotes = FALSE;
  126.  
  127. /* no delim after last word on a line */
  128. #define add_char(c) \
  129. ( \
  130.     (newword ? (newword = FALSE, putc(delim,ofile)) : 0), \
  131.     putc((c),ofile), \
  132.     wordlen++ \
  133. )
  134.  
  135. /* don't count the backslash, but do check for delim */
  136. #define add_esc_char(c) ( add_char('\\'), putc((c),ofile) )
  137. #define add_dec_char(c) ( add_char('\\'), fprintf(ofile,"%3.3d",(char)(c)) )
  138.  
  139. /* ignore empty words except at beginning of a line */
  140. #define end_word() \
  141. ( \
  142.     (wordlen > 0 || linelen == 0) ? ( \
  143.     newword = TRUE, \
  144.     wordlen = 0, \
  145.     linelen++ \
  146.     ) : (0) \
  147. )
  148.  
  149. /* no delim at beginning of line; ignore empty lines */
  150. #define end_line() \
  151. ( \
  152.     (wordlen > 0) ? linelen++ : (0), \
  153.     newword = FALSE, \
  154.     wordlen = 0, \
  155.     (linelen > 0) ? ( \
  156.     putc('\n', ofile), \
  157.     linelen = 0 \
  158.     ) : (0) \
  159. )
  160.  
  161.  
  162.  
  163. while ( ! feof(ifile) ) {
  164.  
  165.     c = getc(ifile);
  166.     switch (c) {
  167.     case EOF:
  168.         break;
  169.     case ' ':
  170.     case '\t':
  171.         if ( inquotes )
  172.         add_esc_char(c);
  173.         else {
  174.         end_word();
  175.         while ( (c = getc(ifile)) != EOF && (c == ' ' || c == '\t') );
  176.         ungetc(c, ifile);
  177.         }
  178.         break;
  179.     case '\n':
  180.         if ( inquotes )
  181.         ; /* do nothing */
  182.         else if ( inbrackets )
  183.         end_word();
  184.         else
  185.         end_line();
  186.         break;
  187.     case ';':
  188.         if ( inquotes )
  189.         add_esc_char(c);
  190.         else {
  191.         if ( ! inbrackets )
  192.             end_line();
  193.         while ( (c = getc(ifile)) != EOF && c != '\n' ); /* skip */
  194.         }
  195.         break;
  196.     case '"':
  197.         if ( inquotes )
  198.         inquotes = FALSE;
  199.         else
  200.         inquotes = TRUE;
  201.         break;
  202.     case '(':
  203.         if ( inbrackets || inquotes )
  204.         add_esc_char(c);
  205.         else {
  206.         inbrackets = TRUE;
  207.         end_word();
  208.         }
  209.         break;
  210.     case ')':
  211.         if ( inbrackets && (! inquotes) ) {
  212.         inbrackets = FALSE;
  213.         end_word();
  214.         } else
  215.         add_esc_char(c);
  216.         break;
  217.     case '\\':
  218.         if ( (c = getc(ifile)) == EOF ) {
  219.         add_esc_char('\\');
  220.         end_line();
  221.         } else if ( c == '\n' ) {
  222.         if ( ! inquotes )
  223.             end_word();
  224.         } else if ( c == delim )
  225.         add_dec_char(c);    /* no delims inside fields */
  226.         else
  227.         add_esc_char(c);
  228.         break;
  229.     case '.':
  230.     case '@':
  231.         if ( inquotes )
  232.         add_esc_char(c);
  233.         else
  234.         add_char(c);
  235.         break;
  236.     default:
  237.         if ( c == delim )
  238.         add_dec_char(c);    /* no delims inside fields */
  239.         else
  240.         add_char(c);
  241.     }
  242. }
  243.  
  244. }
  245.  
  246.